package com.uw.uwregistry.cluster;

import com.uw.uwregistry.http.HttpInvoker;
import com.uw.uwregistry.meta.ServerMeta;
import com.uw.uwregistry.service.RegistryContainer;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 集群监控
 */
@Slf4j
public class ClusterMonitor {

    private final Cluster cluster;

    public ClusterMonitor(Cluster cluster) {
        this.cluster = cluster;
    }

    private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

    private final static long DELAY = 5_000;

    public void start() {
        // 启动线程循环检测更新节点信息，触发选举集群主节点
        executor.scheduleWithFixedDelay(() -> {
            try {
                updateServerNodes(); // 更新节点信息
                electLeader(); // 选举集群主节点
                syncRegistryContainer(); // 同步注册中心容器
            } catch (Exception ex) {
                log.error("更新节点信息失败", ex);
            }
        }, 0L, DELAY, TimeUnit.MILLISECONDS);
    }

    public void stop() {
        executor.shutdown();
    }

    private void updateServerNodes() {
        for (ServerMeta node : cluster.getNodeList()) {
            try {
                ServerMeta serverMeta = HttpInvoker.httpGet(node.getUrl() + "/info", ServerMeta.class);
                if (serverMeta != null) {
                    node.setStatus(true);
                    node.setLeader(serverMeta.isLeader());
                    node.setVersion(serverMeta.getVersion());
                } else {
                    node.setStatus(false);
                }
            } catch (Exception ex) {
                log.error(" ==> updateServerNodes exception", ex);
                node.setStatus(false);
                node.setLeader(false);
            }
        }
    }

    private void electLeader() {
        new Election().electLeader(cluster.getNodeList());
    }


    private void syncRegistryContainer() {
        ServerMeta leader = cluster.leader();
        ServerMeta self = cluster.self();
        log.debug(" ===> leader version:{}, my version:{}", leader.getVersion(), self.getVersion());
        if (!self.isLeader() && self.getVersion() < leader.getVersion()) {
            log.debug(" ===> 主节点更新，同步快照，leader:{}", leader);
            RegistryContainer.Snapshot snapshot = HttpInvoker.httpGet(leader.getUrl() + "/snapshot", RegistryContainer.Snapshot.class);
            log.debug(" ===> sync snapshot:{}", snapshot);
            RegistryContainer.restore(snapshot);
        }
    }


}
